package service

import (
	"duoke/internal/dao"
	"duoke/model"
	"duoke/utils/orm"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/gconv"
	"math/rand"
	"time"
)

var Carmine = new(carmineService)

type carmineService struct{}

const (
	TableCarmine     = "carmine"
	TableUserCarmine = "user_carmine"
)

func (s *carmineService) Save(c *gin.Context, req *model.ReqCarmine) error {
	account, err := Request.Account(c)
	if err != nil {
		return err
	}
	if req.Id == 0 {
		get, err := orm.Db.OrderBy("weight desc").Table(TableCarmine).Cols("weight").Get(&req.Weight)
		if err == nil || get {
			req.Weight += 1
		}
	}
	req.Acid = account.Id
	// 转换为 map 并忽略零值字段
	result, err := dao.Carmine.Ctx(c).OmitEmpty().Save(&req)
	affected, err := result.RowsAffected()
	if err != nil || affected == 0 {
		return errors.New("修改失败")
	}
	if req.Id != 0 {
		// 修改的时候 修改用户未使用的卡密
		carmine := map[string]any{
			"carmine_id":      req.Id,
			"title":           req.Title,
			"tag":             req.Tag,
			"is_effective":    req.IsEffective,
			"expiration_date": req.ExpirationDate,
			"expiration_day":  req.ExpirationDay,
			"cover":           req.Cover,
			"sub_mchId":       req.SubMchId,
			"acid":            req.Acid,
			"types":           req.Types,
		}
		err = UserCarmine.WhereSave(c, carmine, &model.SearchUserCarmine{IsUse: 2, CarmineId: req.Id})
	}
	return err
}

func (s *carmineService) Info(c *gin.Context, req *model.ReqCarmine) (*model.ReqCarmine, error) {
	account, err := Request.Account(c)
	g2 := g.Map{}
	if req.Id != 0 {
		g2["id=?"] = req.Id
	}
	if req.Types != 0 {
		g2["types=?"] = req.Types
	}
	if account.Id > 0 {
		req.Acid = account.Id
	}
	err = dao.Carmine.Ctx(c).Where(g2).Scan(&req)
	if err != nil {
		return nil, errors.New("数据不存在")
	}
	if req.ExpirationDate != nil {
		time, err := gtime.StrToTime(gconv.String(req.ExpirationDate))
		if err != nil {
			return nil, err
		}
		req.ExpirationDate = time.Format("Y-m-d H:i:s")
	}
	return req, nil
}

func (s *carmineService) List(c *gin.Context, req *model.SearchCarmine) (*model.RspList, error) {
	account, err := Request.Account(c)
	if err != nil || account.Id == 0 {
		return nil, errors.New("用户数据不存在")
	}
	var m []model.ReqCarmine
	gmap := g.Map{}
	if req.Keyword != "" {
		gmap["title like ?"] = "%" + req.Keyword + "%"
	}
	if req.Types != 0 {
		gmap["types=?"] = req.Types
	}
	if req.UserId != 0 {
		gmap["user_id=?"] = req.UserId
	}
	var count int
	// 计算偏移量
	err = dao.Carmine.Ctx(c).Where(gmap).Page(req.PageNo, req.PageSize).OrderDesc("id").
		ScanAndCount(&m, &count, false)
	if err != nil {
		return nil, err
	}
	for k, item := range m {
		s2 := gconv.String(item.ExpirationDate)
		m[k].ExpirationDate = ""
		if s2 != "" {
			m[k].ExpirationDate = gtime.NewFromStr(s2).Format("Y-m-d H:i:s")
		}
	}
	return &model.RspList{
		Total: int64(count),
		List:  &m,
	}, nil
}

func (s *carmineService) Del(c *gin.Context, id int) error {
	del, err := orm.Db.Where("id=?", id).Table(TableCarmine).Delete(&model.ReqCarmine{})
	if del == 0 || err != nil {
		return errors.New("删除失败")
	}
	return nil
}

// GeneratedCode 生成卡密 只有限定卡密能生成
func (s *carmineService) GeneratedCode(c *gin.Context, req *model.SearchUserCarmine) error {
	account, err := Request.Account(c)
	if err != nil {
		return err
	}
	var add []model.ReqUserCarmine
	info, err := s.Info(c, &model.ReqCarmine{Id: req.FromId, Types: req.Types})
	if err != nil {
		return err
	}
	session := orm.Db.NewSession()
	defer session.Close()
	err = session.Begin()
	if err != nil {
		return errors.New("事务开启失败")
	}
	for i := 0; i < req.Number; i++ {
		add = append(add, model.ReqUserCarmine{
			CarmineId:     info.Id,
			Cover:         info.Cover,
			Tag:           info.Tag,
			Title:         info.Title,
			IsEffective:   info.IsEffective,
			Code:          s.GenerateCarmineCode(),
			SubMchId:      req.SubMchId,
			Acid:          account.Id,
			Types:         req.Types,
			ExpirationDay: info.ExpirationDay,
		})
		if info.IsEffective == 1 && info.ExpirationDate != "" {
			add[i].ExpirationDate = gconv.String(info.ExpirationDate)
		} else {
			add[i].ExpirationDate = nil
		}
		// 如果是有用户id 卡券IsEffective = 2的话 则有效期等于 当天加上ExpirationDay
		if req.UserId != 0 {
			add[i].UserId = req.UserId
			add[i].IsUse = 4
			if info.IsEffective == 2 {
				add[i].ExpirationDate =
					gtime.Now().AddDate(0, 0, info.ExpirationDay).Format("Y-m-d H:i:s")
			}
		} else {
			add[i].IsUse = 2
		}
	}
	insert, err := session.Table(TableUserCarmine).Omit("nickname,avatar").
		InsertMulti(add)
	if err != nil || insert == 0 {
		session.Rollback()
		return err
	}
	update, err := session.Where("id=?", info.Id).Table(TableCarmine).Incr("generator", req.Number).
		Update(new(model.ReqCarmine))
	if update == 0 || err != nil {
		session.Rollback()
		return errors.New("修改失败")
	}
	err = session.Commit()
	if err != nil {
		session.Rollback()
		return err
	}
	return nil
}

// GenerateCarmineCode 生成卡密
func (s *carmineService) GenerateCarmineCode() string {
	const letterBytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	const segmentLength = 4
	const segmentCount = 4
	rand.Seed(time.Now().UnixNano())
	b := make([]byte, segmentLength*segmentCount+(segmentCount-1))

	for i, j := 0, 0; i < len(b); i++ {
		if (i+1)%(segmentLength+1) == 0 {
			b[i] = '-'
		} else {
			b[i] = letterBytes[rand.Intn(len(letterBytes))]
		}
		j++
	}
	return string(b)
}
